package panda.query.condition;

import panda.query.scan.Scanner;
import panda.query.struct.Attribute;
import panda.query.struct.Constant;
import panda.query.struct.NullConstant;
import panda.query.tree.QueryTreeNode;
import panda.server.Panda;
import panda.syntax.SelectStm;
import panda.transaction.Transaction;

public class AnyExpression implements BooleanExpression {
	
	public final static int EQ = 0, NEQ = 1, LT = 2, GT = 3, LTE = 4, GTE = 5;
	
	private int op;
	QueryTreeNode tn = null;
	ValueExpression expr;
	SelectStm stm;

	public AnyExpression(ValueExpression expr, int op, SelectStm stm) {
		this.op = op;
		this.stm = stm;
		this.expr = expr;
	}
	
	@Override
	public int equateWithConstant(Attribute attr) {
		return 0;
	}

	@Override
	public int isSatisfied(Scanner s, Transaction tx) {
		if (tn == null) tn = Panda.getPlanner().executeSubQuery(stm, tx);
		
		for (AttributeName a : stm.subReferring)
			a.stubValue(s.getValue(a.getAttribute()));
		
		Scanner sc = tn.open();
		
		Constant ev = expr.evaluate(s, tx);
		if (ev instanceof NullConstant) return 0;
		
		boolean unk = false;
		
		while (sc.next()) {
			Constant sv = null;
			
			for (Attribute a : tn.getSchema().getAllAttributes())
				sv = sc.getValue(a);

			int res = satisfyRel(ev, sv);
			
			if (res > 0) {
				sc.close();
				return 1;
			}
		}
		
		sc.close();
		if (unk) return 0; else return -1;
	}
	
	public int satisfyRel(Constant a, Constant b) {
		int res = a.compareTo(b);
		
		switch (op) {
		case EQ:
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res == 0)
				return 1;
			return -1;
		case NEQ: 
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res != 0)
				return 1;
			return -1;
		case LT:
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res < 0)
				return 1;
			return -1;
		case GT:
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res > 0)
				return 1;
			return -1;
		case LTE:
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res <= 0)
				return 1;
			return -1;
		case GTE:
			if (Math.abs(res) == Integer.MAX_VALUE)
				return 0;
			if (res >= 0)
				return 1;
			return -1;
		}
		return -1;
	}

	@Override
	public double reductionFactor(QueryTreeNode n) {
		return 1;
	}

}
